﻿using System;
using System.Collections;
using System.Linq.Expressions;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using élénkPróbája.helpers;
using élénkPróbája.native;
using élénkPróbája.native.@select;
using élénkPróbája.results;
using élénkPróbája.validators;

namespace élénkPróbája.extentions
{
    public static class DefaultValidatorExtensions
    {
        /// <summary>
        /// Defines a 'not null' validator on the current rule builder. 
        /// Validation will fail if the property is null.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="testAdmin">The test admin on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> NotNull<T, TProperty>(this ITestAdmin<T, TProperty> testAdmin)
        {
            return testAdmin.SetValidator(new PopulatedValidator());
        }
        /// <summary>
		/// Defines a 'not null' validator on the current rule builder. 
		/// Validation will fail if the property is null.
		/// </summary>
		/// <typeparam name="T">Type of object being validated</typeparam>
		/// <typeparam name="TProperty">Type of property being validated</typeparam>
		/// <param name="testAdmin">The rule builder on which the validator should be defined</param>
		/// <returns></returns>
		public static ITestAdminOptions<T, TProperty> Null<T, TProperty>(this ITestAdmin<T, TProperty> testAdmin)
        {
            return testAdmin.SetValidator(new NullValidator());
        }
        /// <summary>
        /// Defines a 'not empty' validator on the current rule builder.
        /// Validation will fail if the property is null, an empty or the default value for the type (for example, 0 for integers)
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="testAdmin">The rule builder on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> NotEmpty<T, TProperty>(this ITestAdmin<T, TProperty> testAdmin)
        {
            return testAdmin.SetValidator(new PopulatedValidator(default(TProperty)));
        }
        /// <summary>
		/// Defines a 'empty' validator on the current rule builder.
		/// Validation will fail if the property is not null, an empty or the default value for the type (for example, 0 for integers)
		/// </summary>
		/// <typeparam name="T">Type of object being validated</typeparam>
		/// <typeparam name="TProperty">Type of property being validated</typeparam>
		/// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
		/// <returns></returns>
		public static ITestAdminOptions<T, TProperty> Empty<T, TProperty>(this ITestAdmin<T, TProperty> testAdmin)
        {
            return testAdmin.SetValidator(new EmptyValidator(default(TProperty)));
        }

        /// <summary>
        /// Defines a length validator on the current rule builder, but only for string properties.
        /// Validation will fail if the length of the string is outside of the specifed range. The range is inclusive.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Length<T>(this ITestAdmin<T, string> ruleBuilder, int min, int max)
        {
            return ruleBuilder.SetValidator(new LengthValidator(min, max));
        }

        /// <summary>
        /// Defines a length validator on the current rule builder, but only for string properties.
        /// Validation will fail if the length of the string is outside of the specifed range. The range is inclusive.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Length<T>(this ITestAdmin<T, string> ruleBuilder, Func<T, int> min, Func<T, int> max)
        {
            return ruleBuilder.SetValidator(new LengthValidator(min.CoerceToNonGeneric(), max.CoerceToNonGeneric()));
        }

        /// <summary>
        /// Defines a length validator on the current rule builder, but only for string properties.
        /// Validation will fail if the length of the string is not equal to the length specified.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Length<T>(this ITestAdmin<T, string> ruleBuilder, int exactLength)
        {
            return ruleBuilder.SetValidator(new ExactLengthValidator(exactLength));
        }

        /// <summary>
        /// Defines a length validator on the current rule builder, but only for string properties.
        /// Validation will fail if the length of the string is not equal to the length specified.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Length<T>(this ITestAdmin<T, string> ruleBuilder, Func<T, int> exactLength)
        {
            return ruleBuilder.SetValidator(new ExactLengthValidator(exactLength.CoerceToNonGeneric()));
        }

        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda does not match the regular expression.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The regular expression to check the value against.</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Matches<T>(this ITestAdmin<T, string> ruleBuilder, string expression)
        {
            return ruleBuilder.SetValidator(new RegularExpressionValidator(expression));
        }

        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda does not match the regular expression.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The regular expression to check the value against.</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Matches<T>(this ITestAdmin<T, string> ruleBuilder, Func<T, string> expression)
        {
            return ruleBuilder.SetValidator(new RegularExpressionValidator(expression.CoerceToNonGeneric()));
        }


        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda does not match the regular expression.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="regex">The regular expression to use</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Matches<T>(this ITestAdmin<T, string> ruleBuilder, Regex regex)
        {
            return ruleBuilder.SetValidator(new RegularExpressionValidator(regex));
        }

        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda does not match the regular expression.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="regex">The regular expression to use</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Matches<T>(this ITestAdmin<T, string> ruleBuilder, Func<T, Regex> regex)
        {
            return ruleBuilder.SetValidator(new RegularExpressionValidator(regex.CoerceToNonGeneric()));
        }


        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda does not match the regular expression.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The regular expression to check the value against.</param>
        /// <param name="options">Regex options</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Matches<T>(this ITestAdmin<T, string> ruleBuilder, string expression, RegexOptions options)
        {
            return ruleBuilder.SetValidator(new RegularExpressionValidator(expression, options));
        }

        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda does not match the regular expression.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The regular expression to check the value against.</param>
        /// <param name="options">Regex options</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> Matches<T>(this ITestAdmin<T, string> ruleBuilder, Func<T, string> expression, RegexOptions options)
        {
            return ruleBuilder.SetValidator(new RegularExpressionValidator(expression.CoerceToNonGeneric(), options));
        }

        /// <summary>
        /// Defines a regular expression validator on the current rule builder, but only for string properties.
        /// Validation will fail if the value returned by the lambda is not a valid email address.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, string> EmailAddress<T>(this ITestAdmin<T, string> ruleBuilder)
        {
            return ruleBuilder.SetValidator(new EmailValidator());
        }

        /// <summary>
        /// Defines a 'not equal' validator on the current rule builder.
        /// Validation will fail if the specified value is equal to the value of the property.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="toCompare">The value to compare</param>
        /// <param name="comparer">Equality comparer to use</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> NotEqual<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                               TProperty toCompare, IEqualityComparer comparer = null)
        {
            return ruleBuilder.SetValidator(new UnequalValidator(toCompare, comparer));
        }

        /// <summary>
        /// Defines a 'not equal' validator on the current rule builder using a lambda to specify the value.
        /// Validation will fail if the value returned by the lambda is equal to the value of the property.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">A lambda expression to provide the comparison value</param>
        /// <param name="comparer">Equality Comparer to use</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> NotEqual<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                               Expression<Func<T, TProperty>> expression, IEqualityComparer comparer = null)
        {
            var func = expression.Compile();
            return ruleBuilder.SetValidator(new UnequalValidator(func.CoerceToNonGeneric(), expression.GetMember(), comparer));
        }

        /// <summary>
        /// Defines an 'equals' validator on the current rule builder. 
        /// Validation will fail if the specified value is not equal to the value of the property.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="toCompare">The value to compare</param>
        /// <param name="comparer">Equality Comparer to use</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> Equal<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, TProperty toCompare, IEqualityComparer comparer = null)
        {
            return ruleBuilder.SetValidator(new EqualValidator(toCompare, comparer));
        }

        /// <summary>
        /// Defines an 'equals' validator on the current rule builder using a lambda to specify the comparison value.
        /// Validation will fail if the value returned by the lambda is not equal to the value of the property.
        /// </summary>
        /// <typeparam name="T">The type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">A lambda expression to provide the comparison value</param>
        /// <param name="comparer">Equality comparer to use</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> Equal<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression, IEqualityComparer comparer = null)
        {
            var func = expression.Compile();
            return ruleBuilder.SetValidator(new EqualValidator(func.CoerceToNonGeneric(), expression.GetMember(), comparer));
        }

        /// <summary>
        /// Defines a predicate validator on the current rule builder using a lambda expression to specify the predicate.
        /// Validation will fail if the specified lambda returns false.
        /// Validation will succeed if the specifed lambda returns true.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="predicate">A lambda expression specifying the predicate</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> Must<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Func<TProperty, bool> predicate)
        {
            predicate.Guard("Cannot pass a null predicate to Must.");

            return ruleBuilder.Must((x, val) => predicate(val));
        }

        /// <summary>
        /// Defines a predicate validator on the current rule builder using a lambda expression to specify the predicate.
        /// Validation will fail if the specified lambda returns false.
        /// Validation will succeed if the specifed lambda returns true.
        /// This overload accepts the object being validated in addition to the property being validated.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="predicate">A lambda expression specifying the predicate</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> Must<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Func<T, TProperty, bool> predicate)
        {
            predicate.Guard("Cannot pass a null predicate to Must.");
            return ruleBuilder.Must((x, val, propertyValidatorContext) => predicate(x, val));
        }

        /// <summary>
        /// Defines a predicate validator on the current rule builder using a lambda expression to specify the predicate.
        /// Validation will fail if the specified lambda returns false.
        /// Validation will succeed if the specifed lambda returns true.
        /// This overload accepts the object being validated in addition to the property being validated.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="predicate">A lambda expression specifying the predicate</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> Must<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Func<T, TProperty, PropertyValidatorContext, bool> predicate)
        {
            predicate.Guard("Cannot pass a null predicate to Must.");
            return ruleBuilder.SetValidator(new PredicateValidator((instance, property, propertyValidatorContext) => predicate((T)instance, (TProperty)property, propertyValidatorContext)));
        }

        /// <summary>
        /// Defines an asynchronous predicate validator on the current rule builder using a lambda expression to specify the predicate.
        /// Validation will fail if the specified lambda returns false.
        /// Validation will succeed if the specifed lambda returns true.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="predicate">A lambda expression specifying the predicate</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> MustAsync<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Func<TProperty, CancellationToken, Task<bool>> predicate)
        {
            predicate.Guard("Cannot pass a null predicate to Must.");

            return ruleBuilder.MustAsync((x, val, ctx, cancel) => predicate(val, cancel));
        }

        /// <summary>
        /// Defines an asynchronous predicate validator on the current rule builder using a lambda expression to specify the predicate.
        /// Validation will fail if the specified lambda returns false.
        /// Validation will succeed if the specifed lambda returns true.
        /// This overload accepts the object being validated in addition to the property being validated.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="predicate">A lambda expression specifying the predicate</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> MustAsync<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Func<T, TProperty, CancellationToken, Task<bool>> predicate)
        {
            predicate.Guard("Cannot pass a null predicate to Must.");
            return ruleBuilder.MustAsync((x, val, propertyValidatorContext, cancel) => predicate(x, val, cancel));
        }

        /// <summary>
        /// Defines an asynchronous predicate validator on the current rule builder using a lambda expression to specify the predicate.
        /// Validation will fail if the specified lambda returns false.
        /// Validation will succeed if the specifed lambda returns true.
        /// This overload accepts the object being validated in addition to the property being validated.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="predicate">A lambda expression specifying the predicate</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> MustAsync<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, Func<T, TProperty, PropertyValidatorContext, CancellationToken, Task<bool>> predicate)
        {
            predicate.Guard("Cannot pass a null predicate to Must.");
            return ruleBuilder.SetValidator(new AsyncPredicateValidator((instance, property, propertyValidatorContext, cancel) => predicate((T)instance, (TProperty)property, propertyValidatorContext, cancel)));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder. 
        /// The validation will succeed if the property value is less than the specified value.
        /// The validation will fail if the property value is greater than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> LessThan<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                               TProperty valueToCompare)
            where TProperty : IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new LesserValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder. 
        /// The validation will succeed if the property value is less than the specified value.
        /// The validation will fail if the property value is greater than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> LessThan<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder,
                                                                               TProperty valueToCompare)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new LesserValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'less than or equal' validator on the current rule builder. 
        /// The validation will succeed if the property value is less than or equal to the specified value.
        /// The validation will fail if the property value is greater than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> LessThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, TProperty> ruleBuilder, TProperty valueToCompare) where TProperty : IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new LesserOrEqualValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'less than or equal' validator on the current rule builder. 
        /// The validation will succeed if the property value is less than or equal to the specified value.
        /// The validation will fail if the property value is greater than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> LessThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, Nullable<TProperty>> ruleBuilder, TProperty valueToCompare) where TProperty : struct, IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new LesserOrEqualValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'greater than' validator on the current rule builder. 
        /// The validation will succeed if the property value is greater than the specified value.
        /// The validation will fail if the property value is less than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> GreaterThan<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, TProperty valueToCompare)
            where TProperty : IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new ExceedValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'greater than' validator on the current rule builder. 
        /// The validation will succeed if the property value is greater than the specified value.
        /// The validation will fail if the property value is less than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty?> GreaterThan<T, TProperty>(this ITestAdmin<T, TProperty?> ruleBuilder, TProperty valueToCompare)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new ExceedValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'greater than or equal' validator on the current rule builder. 
        /// The validation will succeed if the property value is greater than or equal the specified value.
        /// The validation will fail if the property value is less than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> GreaterThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, TProperty> ruleBuilder, TProperty valueToCompare) where TProperty : IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new ExceedOrEqualValidator(valueToCompare));
        }

        /// <summary>
        /// Defines a 'greater than or equal' validator on the current rule builder. 
        /// The validation will succeed if the property value is greater than or equal the specified value.
        /// The validation will fail if the property value is less than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> GreaterThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, Nullable<TProperty>> ruleBuilder, TProperty valueToCompare) where TProperty : struct, IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new ExceedOrEqualValidator(valueToCompare));
        }


        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than the specified value.
        /// The validation will fail if the property value is greater than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">A lambda that should return the value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> LessThan<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                               Expression<Func<T, TProperty>> expression)
            where TProperty : IComparable<TProperty>, IComparable
        {
            expression.Guard("Cannot pass null to LessThan");

            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than the specified value.
        /// The validation will fail if the property value is greater than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">A lambda that should return the value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> LessThan<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                               Expression<Func<T, Nullable<TProperty>>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            expression.Guard("Cannot pass null to LessThan");

            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than the specified value.
        /// The validation will fail if the property value is greater than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">A lambda that should return the value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> LessThan<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder,
                                                                                         Expression<Func<T, TProperty>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            expression.Guard("Cannot pass null to LessThan");

            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than the specified value.
        /// The validation will fail if the property value is greater than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">A lambda that should return the value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> LessThan<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder,
                                                                                         Expression<Func<T, Nullable<TProperty>>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            expression.Guard("Cannot pass null to LessThan");

            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than or equal' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than or equal to the specified value.
        /// The validation will fail if the property value is greater than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> LessThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> expression)
            where TProperty : IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserOrEqualValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than or equal' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than or equal to the specified value.
        /// The validation will fail if the property value is greater than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> LessThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, TProperty> ruleBuilder, Expression<Func<T, Nullable<TProperty>>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserOrEqualValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than or equal' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than or equal to the specified value.
        /// The validation will fail if the property value is greater than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> LessThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, Nullable<TProperty>> ruleBuilder, Expression<Func<T, TProperty>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserOrEqualValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than or equal' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is less than or equal to the specified value.
        /// The validation will fail if the property value is greater than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty?> LessThanOrEqualTo<T, TProperty>(
          this ITestAdmin<T, TProperty?> ruleBuilder, Expression<Func<T, TProperty?>> expression)
          where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new LesserOrEqualValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than the specified value.
        /// The validation will fail if the property value is less than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> GreaterThan<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                                  Expression<Func<T, TProperty>> expression)
            where TProperty : IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new ExceedValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than the specified value.
        /// The validation will fail if the property value is less than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> GreaterThan<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder,
                                                                                  Expression<Func<T, Nullable<TProperty>>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new ExceedValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than the specified value.
        /// The validation will fail if the property value is less than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> GreaterThan<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder,
                                                                                  Expression<Func<T, TProperty>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new ExceedValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'less than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than the specified value.
        /// The validation will fail if the property value is less than or equal to the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="expression">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> GreaterThan<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder,
                                                                                  Expression<Func<T, Nullable<TProperty>>> expression)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = expression.Compile();

            return ruleBuilder.SetValidator(new ExceedValidator(func.CoerceToNonGeneric(), expression.GetMember()));
        }

        /// <summary>
        /// Defines a 'greater than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than or equal the specified value.
        /// The validation will fail if the property value is less than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> GreaterThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, TProperty> ruleBuilder, Expression<Func<T, TProperty>> valueToCompare)
            where TProperty : IComparable<TProperty>, IComparable
        {
            var func = valueToCompare.Compile();

            return ruleBuilder.SetValidator(new ExceedOrEqualValidator(func.CoerceToNonGeneric(), valueToCompare.GetMember()));
        }

        /// <summary>
        /// Defines a 'greater than' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than or equal the specified value.
        /// The validation will fail if the property value is less than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> GreaterThanOrEqualTo<T, TProperty>(
            this ITestAdmin<T, TProperty> ruleBuilder, Expression<Func<T, Nullable<TProperty>>> valueToCompare)
            where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = valueToCompare.Compile();

            return ruleBuilder.SetValidator(new ExceedOrEqualValidator(func.CoerceToNonGeneric(), valueToCompare.GetMember()));
        }

        /// <summary>
        /// Defines a 'greater than or equal to' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than or equal the specified value.
        /// The validation will fail if the property value is less than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty?> GreaterThanOrEqualTo<T, TProperty>(this ITestAdmin<T, TProperty?> ruleBuilder, Expression<Func<T, TProperty?>> valueToCompare)
          where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = valueToCompare.Compile();
            return ruleBuilder.SetValidator(new ExceedOrEqualValidator(func.CoerceToNonGeneric(), valueToCompare.GetMember()));
        }

        /// <summary>
        /// Defines a 'greater than or equal to' validator on the current rule builder using a lambda expression. 
        /// The validation will succeed if the property value is greater than or equal the specified value.
        /// The validation will fail if the property value is less than the specified value.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="valueToCompare">The value being compared</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty?> GreaterThanOrEqualTo<T, TProperty>(
          this ITestAdmin<T, TProperty?> ruleBuilder, Expression<Func<T, TProperty>> valueToCompare)
          where TProperty : struct, IComparable<TProperty>, IComparable
        {
            var func = valueToCompare.Compile();

            return ruleBuilder.SetValidator(new ExceedOrEqualValidator(func.CoerceToNonGeneric(), valueToCompare.GetMember()));
        }

        /// <summary>
        /// Validates certain properties of the specified instance.
        /// </summary>
        /// <param name="validator">The current validator</param>
        /// <param name="instance">The object to validate</param>
        /// <param name="propertyExpressions">Expressions to specify the properties to validate</param>
        /// <returns>A ValidationResult object containing any validation failures</returns>
        public static ValidationResult Validate<T>(this IValidator<T> validator, T instance, params Expression<Func<T, object>>[] propertyExpressions)
        {
            var context = new LitmusValidationContext<T>(instance, new PropChain(), PropValidatorSelector.FromExpressions(propertyExpressions));
            return validator.Validate(context);
        }

        /// <summary>
        /// Validates certain properties of the specified instance.
        /// </summary>
        /// <param name="instance">The object to validate</param>
        /// <param name="properties">The names of the properties to validate.</param>
        /// <returns>A ValidationResult object containing any validation failures.</returns>
        public static ValidationResult Validate<T>(this IValidator<T> validator, T instance, params string[] properties)
        {
            var context = new LitmusValidationContext<T>(instance, new PropChain(), new PropValidatorSelector(properties));
            return validator.Validate(context);
        }

        public static ValidationResult Validate<T>(this IValidator<T> validator, T instance, ILitValidatorSelector selector = null, string ruleSet = null)
        {
            if (selector != null && ruleSet != null)
            {
                throw new InvalidOperationException("Cannot specify both an IValidatorSelector and a RuleSet.");
            }

            if (selector == null)
            {
                selector = new LitmusDefaultValidatorSelector();
            }

            if (ruleSet != null)
            {
                var ruleSetNames = ruleSet.Split(',', ';');
                selector = new RulesetValidatorSelector(ruleSetNames);
            }

            var context = new LitmusValidationContext<T>(instance, new PropChain(), selector);
            return validator.Validate(context);
        }

        /// <summary>
        /// Validates certain properties of the specified instance asynchronously.
        /// </summary>
        /// <param name="validator">The current validator</param>
        /// <param name="instance">The object to validate</param>
        /// <param name="propertyExpressions">Expressions to specify the properties to validate</param>
        /// <returns>A ValidationResult object containing any validation failures</returns>
        public static Task<ValidationResult> ValidateAsync<T>(this IValidator<T> validator, T instance, params Expression<Func<T, object>>[] propertyExpressions)
        {
            var context = new LitmusValidationContext<T>(instance, new PropChain(), PropValidatorSelector.FromExpressions(propertyExpressions));
            return validator.ValidateAsync(context);
        }

        /// <summary>
        /// Validates certain properties of the specified instance asynchronously.
        /// </summary>
        /// <param name="instance">The object to validate</param>
        /// <param name="properties">The names of the properties to validate.</param>
        /// <returns>A ValidationResult object containing any validation failures.</returns>
        public static Task<ValidationResult> ValidateAsync<T>(this IValidator<T> validator, T instance, params string[] properties)
        {
            var context = new LitmusValidationContext<T>(instance, new PropChain(), new PropValidatorSelector(properties));
            return validator.ValidateAsync(context);
        }

        public static Task<ValidationResult> ValidateAsync<T>(this IValidator<T> validator, T instance, ILitValidatorSelector selector = null, string ruleSet = null)
        {
            if (selector != null && ruleSet != null)
            {
                throw new InvalidOperationException("Cannot specify both an IValidatorSelector and a RuleSet.");
            }

            if (selector == null)
            {
                selector = new LitmusDefaultValidatorSelector();
            }

            if (ruleSet != null)
            {
                var ruleSetNames = ruleSet.Split(',', ';');
                selector = new PropValidatorSelector(ruleSetNames);
            }

            var context = new LitmusValidationContext<T>(instance, new PropChain(), selector);
            return validator.ValidateAsync(context);
        }

        /// <summary>
        /// Performs validation and then throws an exception if validation fails.
        /// </summary>
        public static void ValidateAndThrow<T>(this IValidator<T> validator, T instance)
        {
            var result = validator.Validate(instance);

            if (!result.IsValid)
            {
                throw new ValidationException(result.Errors);
            }
        }

        /// <summary>
        /// Performs validation asynchronously and then throws an exception if validation fails.
        /// </summary>
        public static Task ValidateAndThrowAsync<T>(this IValidator<T> validator, T instance)
        {
            return validator
                .ValidateAsync(instance)
                .Then(r => r.IsValid ? TaskHelpers.Completed() : TaskHelpers.FromError(new ValidationException(r.Errors)));
        }

        /// <summary>
        /// Defines an 'inclusive between' validator on the current rule builder, but only for properties of types that implement IComparable.
        /// Validation will fail if the value of the property is outside of the specifed range. The range is inclusive.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="from">The lowest allowed value</param>
        /// <param name="to">The highest allowed value</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> InclusiveBetween<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, TProperty from, TProperty to) where TProperty : IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new InclusiveBetweenValidator(from, to));
        }

        /// <summary>
        /// Defines an 'inclusive between' validator on the current rule builder, but only for properties of types that implement IComparable.
        /// Validation will fail if the value of the property is outside of the specifed range. The range is inclusive.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="from">The lowest allowed value</param>
        /// <param name="to">The highest allowed value</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> InclusiveBetween<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder, TProperty from, TProperty to) where TProperty : struct, IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new InclusiveBetweenValidator(from, to));
        }

        /// <summary>
        /// Defines an 'exclusive between' validator on the current rule builder, but only for properties of types that implement IComparable.
        /// Validation will fail if the value of the property is outside of the specifed range. The range is exclusive.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="from">The lowest allowed value</param>
        /// <param name="to">The highest allowed value</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, TProperty> ExclusiveBetween<T, TProperty>(this ITestAdmin<T, TProperty> ruleBuilder, TProperty from, TProperty to) where TProperty : IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new ExclusiveBetweenValidator(from, to));
        }

        /// <summary>
        /// Defines an 'exclusive between' validator on the current rule builder, but only for properties of types that implement IComparable.
        /// Validation will fail if the value of the property is outside of the specifed range. The range is exclusive.
        /// </summary>
        /// <typeparam name="T">Type of object being validated</typeparam>
        /// <typeparam name="TProperty">Type of property being validated</typeparam>
        /// <param name="ruleBuilder">The rule builder on which the validator should be defined</param>
        /// <param name="from">The lowest allowed value</param>
        /// <param name="to">The highest allowed value</param>
        /// <returns></returns>
        public static ITestAdminOptions<T, Nullable<TProperty>> ExclusiveBetween<T, TProperty>(this ITestAdmin<T, Nullable<TProperty>> ruleBuilder, TProperty from, TProperty to) where TProperty : struct, IComparable<TProperty>, IComparable
        {
            return ruleBuilder.SetValidator(new ExclusiveBetweenValidator(from, to));
        }

        /// <summary>
        /// Defines a credit card validator for the current rule builder that ensures that the specified string is a valid credit card number.
        /// </summary>
        public static ITestAdminOptions<T, string> CreditCard<T>(this ITestAdmin<T, string> ruleBuilder)
        {
            return ruleBuilder.SetValidator(new CreditCardValidator());
        }
    }
}